﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;
using Pixysoft.Framework.Reflection;
using System.Xml.Serialization;
using Pixysoft.TestDrivens;
using Pixysoft.Framework.Configurations.Core;
using Pixysoft.Tools;
using Pixysoft.Framework.Verifications;
using System.Threading;


namespace Pixysoft.Framework.Configurations.Controller
{
    class MethodReflectionController
    {
        private static readonly ReaderWriterLock locker = new ReaderWriterLock();

        private const string default_attribute_assembly = "assembly";
        private const string default_attribute_type = "type";
        private const string default_attribute_method = "method";
        private const string default_attribute_parametercount = "parametercount";
        private const string default_attribute_return = "return";
        private const string default_attribute_parameter = "parameter";

        /// <summary>
        /// 方法序列化，输入方法可能是接口，因此需要提供装载的配置
        /// 值类型不参与序列化
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="typename"></param>
        /// <param name="method"></param>
        /// <param name="paras"></param>
        /// <returns></returns>
        public static IXmlNode MethodSerialize(string assemblyName, string typeName, MethodInfo method, params object[] paras)
        {
            ParameterInfo[] parameters = method.GetParameters();

            if (parameters.Length != paras.Length)
                throw Exceptions.VerificationFailedException(assemblyName, typeName, method, paras);

            IXmlNode node = XmlManager.CreateNode(default_attribute_method);

            node.Properties.Add(default_attribute_assembly, assemblyName);
            node.Properties.Add(default_attribute_type, typeName);
            node.Properties.Add(default_attribute_method, method.Name);
            node.Properties.Add(default_attribute_parametercount, parameters.Length.ToString());

            int counter = 0;

            foreach (ParameterInfo parameter in parameters)
            {
                IXmlNode paranode = node.Nodes.Add(default_attribute_parameter);
                paranode.Properties.Add(default_attribute_type, parameter.ParameterType.Name);
                paranode.Properties.Add(default_attribute_parameter, parameter.Name);

                object paravalue = paras[counter++];

                if (paravalue == null)
                    continue;

                Type parameterType = parameter.ParameterType;

                //1,119ms -> 214ms 不序列化

                //1,119ms -> 716ms 过滤值类型

                //不能过滤值 因为反序列化的时候 无法定位方法

                IXmlNode parameterNode = DynamicReflectionController.Serialize(paravalue);

                if (parameterNode != null)
                    paranode.Text = parameterNode.Serialize();
            }

            return node;
        }

        /// <summary>
        /// 方法结构反序列化
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static MethodStructure MethodStructureDeserialize(IXmlNode node)
        {
            string assemblyName = node.Properties[default_attribute_assembly];

            string typeName = node.Properties[default_attribute_type];

            string methodname = node.Properties[default_attribute_method];

            int parametercount = node.Properties.Get<int>(default_attribute_parametercount);

            MethodStructure structure = new MethodStructure();
            structure.AssemblyName = assemblyName;
            structure.TypeName = typeName;
            structure.MethodName = methodname;
            structure.ParameterCount = parametercount;
            return structure;
        }
        /// <summary>
        /// 实例方法反序列化调用
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static object MethodDeserialize(IXmlNode node)
        {
            Type type = GetType(node);

            MethodInfo method = GetMethod(type, node);

            ConstructorInfo constructorInfo =
                type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null, new Type[] { }, null);

            object target = constructorInfo.Invoke(null);

            return method.Invoke(target, GetParameters(method, node));
        }
        /// <summary>
        /// 带映射的实例方法反序列化调用
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="typeName"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static object MethodDeserialize(string assemblyName, string typeName, IXmlNode node)
        {
            Type type = GetType(assemblyName, typeName);

            MethodInfo method = GetMethod(type, node);

            ConstructorInfo constructorInfo =
                type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                null, new Type[] { }, null);

            object target = constructorInfo.Invoke(null);

            return method.Invoke(target, GetParameters(method, node));
        }
        /// <summary>
        /// 可重用对象方法反序列化结果
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static object MethodDeserialize(object target, IXmlNode node)
        {
            Type type = target.GetType();

            MethodInfo method = GetMethod(type, node);

            return method.Invoke(target, GetParameters(method, node));
        }

        private static object[] GetParameters(MethodInfo method, IXmlNode node)
        {
            List<object> list = new List<object>();

            if (node.Properties.Get<int>(default_attribute_parametercount) != method.GetParameters().Length)
                throw Exceptions.ManualVerificationFailedException("count of parameter in request do not match the target.");

            int counter = 0;

            foreach (ParameterInfo parameter in method.GetParameters())
            {
                IXmlNode subnode = node.Nodes[default_attribute_parameter][counter++];

                string content = subnode.Text;

                //由于客户端使用了dynamic 协议不一致 因此服务端也需要切换到dynamic解析

                list.Add(XmlManager.DynamicDeserialize(parameter.ParameterType, content));

            }

            return list.ToArray();
        }

        private static MethodInfo GetMethod(Type type, IXmlNode node)
        {
            string methodname = node.Properties[default_attribute_method];

            int parametercount = node.Properties.Get<int>(default_attribute_parametercount);

            foreach (MethodInfo method in type.GetMethods())
            {
                if (!string.Equals(method.Name, methodname))
                    continue;

                ParameterInfo[] parameters = method.GetParameters();

                if (parameters.Length != parametercount)
                    continue;

                bool founded = true;

                for (int i = 0; i < parametercount; i++)
                {
                    IXmlNode parameternode = node.Nodes[default_attribute_parameter][i];

                    ParameterInfo parameter = parameters[i];

                    string paratypename = parameternode.Properties[default_attribute_type];

                    if (string.Equals(parameter.ParameterType.Name, paratypename))
                        continue;

                    founded = false;
                }

                if (!founded)
                    continue;

                return method;
            }

            throw Exceptions.UnexpectedResultException("load method fail. methodname = " + methodname);
        }

        private static Type GetType(IXmlNode node)
        {
            string assemblyName = node.Properties[default_attribute_assembly];

            string typeName = node.Properties[default_attribute_type];

            Type type = Type.GetType(typeName);

            if (type == null)
            {
                Assembly assembly = GetAssembly(assemblyName);

                type = assembly.GetType(typeName);
            }

            if (type == null)
                throw Exceptions.UnexpectedResultException("load type fail. typename = " + typeName);

            return type;
        }

        private static Type GetType(string assemblyName, string typeName)
        {
            Type type = Type.GetType(typeName);

            if (type == null)
            {
                Assembly assembly = GetAssembly(assemblyName);

                type = assembly.GetType(typeName);
            }

            if (type == null)
                throw Exceptions.UnexpectedResultException("load type fail. typename = " + typeName);

            return type;
        }

        private static Assembly GetAssembly(string assemblyName)
        {
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (string.Equals(Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyName(assembly), assemblyName))
                    return assembly;
            }

            Assembly loadassembly = Pixysoft.Tools.AssemblyHelper.Instance.AssemblyLoadFrom(assemblyName + ".dll");

            if (loadassembly == null)
                throw Exceptions.UnexpectedResultException("load assembly failed. assembly name = " + assemblyName);

            return loadassembly;
        }
    }
}
